# 判断一个数据的类型，可以用type函数和isinstance 函数
# 能用 type 判断的函数也能用 isinstance 函数判断
# 而且 isinstance 函数还可以判断一个变量是否是某些类型中的一种，因此优先使用 isinstance 函数进行类型判断
print(isinstance([1, 2, 3], (list, tuple)))
print(isinstance((1, 2, 3), (list, tuple)))

# 使用 dir 函数可以获得一个对象的所有属性和方法
print(dir("ABC"))

# 类似__xxx__的属性和方法在Python中都是有特殊用途的，比如__len__方法返回长度。在Python中，如果你调用len()函数试图获取一个对象的长度，实际上，在len()函数内部，它自动去调用该对象的__len__()方法，所以，下面的代码是等价的：
print(len("ABC"))
print("ABC".__len__())

# 自己写的类如果也想用 len 函数的话，可以自己写一个__len__方法
class MyDog(object):
    def __len__(self):
        return 100
dog = MyDog()
print(len(dog))

# 配合getattr()、setattr()以及hasattr()，我们可以直接操作一个对象的状态

class MyObject(object):
    def __init__(self):
        self.x = 9
    def power(self):
        return self.x * self.x
obj = MyObject()
print(hasattr(obj, 'x'))

print(getattr(obj, 'x'))

print(hasattr(obj, 'y'))

print(setattr(obj, 'y', 19))

print(getattr(obj, 'y'))

print(obj.y)

# 如果获取一个不存在的属性，可以通过设置默认值的方式来避免报错
print(getattr(obj, 'z', '404'))

print(hasattr(obj, 'power'))

print(getattr(obj, 'power'))

fn = getattr(obj, 'power')
print(fn)
print(fn())

# 什么时候需要获取对象的信息，例如下面这个例子，只有在 fp 里面有 read 方法时才能实现图像流的读取
def readData():
    pass
def readImage(fp):
    if hasattr(fp, 'read'):
        return readData(fp)
    return None
